package search.impl;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class BinaryArray<K, V> implements search.text.SymbolTable {
    private static final int SIZE = 1000;
    private Entry<K, V>[] objects;
    private int n;

    public BinaryArray() {
        objects = new EntryObject[SIZE];
        n = 0;
    }

    public int size() {
        return n;
    }

    public boolean isEmpty() {
        return n == 0;
    }

    public boolean containsKey(Object key) {
        int i = binarySearch(key);
        return i != -1;
    }

    public V get(Object key) throws Exception {
        int i = binarySearch(key);
        if (i == -1) {
            throw new Exception("No se ha encontrado");
        } else {
            return objects[i].getValue();
        }
    }


    public void put(Object key, Object value) {
        int index = binarySearch(key);
        if (isFull()) {
            duplicate();
        }
        if (index >= 0) {
            objects[index] = new EntryObject(key, value);
            return;
        }
        int i = n;
        if (i != 0) {
            while (i > 0 && (key.hashCode() - (objects[i - 1].getKey().hashCode()) < 0)) {
                objects[i] = objects[i - 1];
                i--;
            }
        }
        objects[i] = new EntryObject(key, value);
        n++;
    }

    private int binarySearch(Object key) {
        int hi = n - 1;
        int lo = 0;
        while (hi >= lo) {
            int m = lo + (hi - lo) / 2;
            int cmp = key.hashCode() - (objects[m].getKey().hashCode());
            if (cmp < 0) hi = m - 1;
            else if (cmp > 0) lo = m + 1;
            else if (cmp == 0) return m;
        }
        return -1;
    }

    private void duplicate() {
        Entry<K, V>[] newObjects = new EntryObject[n * 2];
        for (int i = 0; i < objects.length; i++) {
            newObjects[i] = objects[i];
        }
        objects = newObjects;
        n *= 2;
    }

    public void clear() {
        objects = new EntryObject[SIZE];
        n = 0;
    }

    public Set entrySet() {
        Set<Entry<K, V>> set = new HashSet<Entry<K, V>>();
        set.addAll(Arrays.asList(objects));
        return set;
    }

    public boolean isFull() {
        return n == objects.length;
    }
}
